<template>
  <div class="algebra">
    <ul class="list">
      <li v-for="item in elements" :key="item.id" class="list-item">
        <div class="row">
          <div style="margin-right: 8px; position: relative">
            <el-input v-model="item.content" placeholder="请输入" @keydown.enter="handleEnter(item)">
              <template #prefix> {{ item.name }}: &nbsp; </template>
              <template #suffix>
                <!-- 圆点 -->
                <div v-if="
                  ![GeometryType.Slider, GeometryType.Variable].includes(
                    item.type,
                  )
                " class="dot" title="显示/隐藏" :class="{ hide: !item.visible }" @click="handleToggleVisible(item.id)">
                </div>
              </template>
            </el-input>
            <span v-if="item.error" class="error">{{ item.error }}</span>
          </div>
          <el-button size="small" link type="danger" @click="handleRemoveElement(item.id)">
            删除
          </el-button>
        </div>
        <div v-if="
          [GeometryType.Slider, GeometryType.Variable].includes(item.type)
        " style="padding: 12px">
          <div class="row">
            <el-icon class="control-icon" @click="handleSliderSpeed(item, -1)">
              <DArrowLeft />
            </el-icon>
            <div class="speed-text">{{ item.variable.speed }} x</div>
            <el-icon class="control-icon" @click="handleSliderSpeed(item, 1)">
              <DArrowRight />
            </el-icon>
          </div>
          <div class="row">
            <span>{{ item.variable.min }}</span>
            <el-slider v-model="item.variable.value" style="padding: 0 16px" :max="item.variable.max"
              :min="item.variable.min" :step="item.variable.step" @change="
                ($event: number) => updateSlider(item, { value: $event })
              " />
            <span>{{ item.variable.max }}</span>
            <el-icon style="cursor: pointer; margin-left: 8px" :size="24" color="blue"
              @click="updateSlider(item, { playing: !item.variable.playing })">
              <VideoPlay v-if="!item.variable.playing" />
              <VideoPause v-else />
            </el-icon>
          </div>
        </div>
      </li>
      <li class="btn-group">
        <el-input v-model="newElement.content" placeholder="请输入" @keydown.enter="handleNewElementEnter" />
      </li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { useFormulaEditor } from '@/store'
import { FormulaElement, Variable } from '@/store/3d/formulaEditor'
import { FElement, pointer2shape } from '@/views/3d/hooks/useFormulaElement'
import { GeometryType } from '@/graph/3d/config/shapes'
import {
  VideoPlay,
  VideoPause,
  DArrowLeft,
  DArrowRight,
} from '@element-plus/icons-vue'
import { useRenderLoop } from '@tresjs/core'

const { onLoop } = useRenderLoop()

const formulaEditor = useFormulaEditor()
const { playingElements, playingElementsMap } = storeToRefs(formulaEditor)
const { elements } = storeToRefs(formulaEditor)
const newElement = ref(new FElement())
const speedList = [
  0.05, 0.1, 0.15, 0.2, 0.25, 0.35, 0.75, 1, 1.5, 2, 3.5, 4, 5, 6, 7, 10, 15,
  20,
]

const handleEnter = (element: FormulaElement) => {
  pointer2shape(element)
}
const handleNewElementEnter = () => {
  const element = newElement.value.clone()
  element.parse()

  if (element.type === GeometryType.Variable) {
    const el = elements.value.find((v) => v.name === element.name)

    if (el) {
      el.content = element.content
      formulaEditor.updateElement([el])
      newElement.value.reset()
      return
    }
  }

  formulaEditor.addElement(element)
  newElement.value.reset()
}
const handleRemoveElement = (id: string) => {
  formulaEditor.removeElement(id)
}
const handleToggleVisible = (id: string) => {
  formulaEditor.updateElement([
    {
      id,
      visible: !elements.value.find((item) => item.id === id)?.visible,
    },
  ])
}
const handleSliderSpeed = (item: FormulaElement, props: 1 | -1) => {
  const index = speedList.indexOf(item.variable.speed)
  const _index = index + props
  if (_index < 0 || _index >= speedList.length) {
    return
  }
  const speed = speedList[_index]
  updateSlider(item, { speed })
}

const updateSlider = (item: FormulaElement, props: Partial<Variable> = {}) => {
  const variable = Object.assign(item.variable, props)

  const { value, min, max, step } = variable
  const content =
    item.type === GeometryType.Slider
      ? `Slider(${value}, ${min}, ${max}, ${step})`
      : `${item.name}=${value}`

  formulaEditor.updateElement([
    { id: item.id, variable, content, result: value },
  ])

  if ('playing' in props) {
    const el = playingElementsMap.value
    if (el.has(item.id)) {
      el.delete(item.id)
    }
    else {
      el.add(item.id)
    }
    formulaEditor.updatePlayingElement(el)
  }
  else {
    pointer2shape(item)
  }
}

onLoop(({ delta }) => {
  playingElements.value.forEach((element) => {
    const { value, step, min, max, direction, speed } = element.variable

    const _vlaue = Math.min(
      max,
      Math.max(min, value + step * direction * delta * 25 * speed),
    )
    const dir = _vlaue >= max ? -1 : _vlaue <= min ? 1 : direction

    // _value 保留两位小数点
    const __value = Number(_vlaue.toFixed(2))

    updateSlider(element, { value: __value, direction: dir })
  })
})
</script>

<style lang="scss" scoped>
.algebra {
  user-select: none;
}

.list {
  height: 750px;
  overflow-y: auto;

  .list-item+.list-item {
    margin-top: 18px;
  }

  .btn-group {
    margin-top: 18px;
  }
}

.dot {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background-color: #409eff;
  border: 1px solid #659cd3;
  cursor: pointer;

  &.hide {
    background-color: red;
  }
}

.control-icon {
  cursor: pointer;
}

.speed-text {
  width: 80px;
  text-align: center;
}

.row {
  display: flex;
  align-items: center;
}

.error {
  position: absolute;
  top: 100%;
  left: 0;
  color: #f56c6c;
  font-size: 12px;
}
</style>
